﻿using System;
using System.Runtime.CompilerServices;
using SunnyTrader.Common;

namespace QuantBox.XApi
{
    internal class SgdConvert
    {
        private const string SgdClientId = "Sgd";

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int GetDate(string date)
        {
            if (string.IsNullOrEmpty(date)) {
                date = DateTime.Today.ToString("yyyyMMdd");
            }
            return string.IsNullOrEmpty(date) ? 99991231 : int.Parse(date);
        }

        public static int GetTime(string time)
        {
            if (string.IsNullOrEmpty(time)) 
            {
                time = DateTime.Now.ToString("HHmmss");
            }

            if (time.Length == 6)
            {
                if (time[1] != ':' && time[2] != ':')
                {
                    return int.Parse(time);
                }
            }
            if (time.Length == 8)
            {
                return int.Parse(time.Substring(0, 2)) * 10000
                       + int.Parse(time.Substring(3, 2)) * 100
                       + int.Parse(time.Substring(6, 2));
            }

            var item = time.Split(':');
            if (item.Length >= 3)
            {
                return int.Parse(item[0]) * 10000
                       + int.Parse(item[1]) * 100
                       + int.Parse(item[2]);
            }

            return 0;
        }

        public static PositionField GetPositionField(InvestorPositionField data)
        {
            var position = new PositionField();
            position.InstrumentID = data.Code;
            position.Symbol = data.Code;
            position.AccountID = data.InvestorID;
            position.Position = data.Position;
            position.OpenCost = data.OpenCost;
            position.PositionCost = data.PositionCost;
            position.TodayPosition = data.TodayPosition;
            position.HistoryPosition = data.YesterdayPosition;
            position.Side = GetPositionSide(data.PosiDirection);
            position.HedgeFlag = GetHedgeFlag(data.HedgeFlag);
            return position;
        }

        public static PositionSide GetPositionSide(EnumPosiDirectionType direction)
        {
            return direction switch
            {
                EnumPosiDirectionType.Short => PositionSide.Short,
                _ => PositionSide.Long,
            };
        }

        public static AccountField GetAccountField(TradingAccountField data)
        {
            var account = new AccountField();
            account.AccountID = data.AccountID;
            account.ClientID = data.TradingDay;
            account.PreBalance = data.PreBalance;
            account.CurrMargin = data.CurrMargin;
            account.Commission = data.Commission;
            account.CloseProfit = data.CloseProfit;
            account.PositionProfit = data.PositionProfit;
            account.Balance = data.Balance;
            account.Available = data.Available;
            account.Deposit = data.Deposit;
            account.Withdraw = data.Withdraw;
            account.WithdrawQuota = data.WithdrawQuota;
            return account;
        }

        public static OrderField GetOrderField(OrderInforField data)
        {
            var order = new OrderField();
            order.ID = data.OrderRef;
            order.LocalID = data.OrderRef;
            order.OrderID = data.OrderSysID;
            order.InstrumentID = data.Code;
            order.Qty = data.VolumeTotal;
            order.ReserveInt32 = data.VolumeTraded;
            order.Side = GetOrderSide(data.Direction);
            order.OpenClose = GetOpenClose(data.Offset);
            order.HedgeFlag = GetHedgeFlag(data.HedgeFlag);
            order.Price = data.LimitPrice;
            order.TimeInForce = TimeInForce.IOC;
            order.Type = GetOrderPriceType(data.OrderPriceType);
            order.Status = GetOrderStatus(data.OrderStatus);
            order.ExecType = GetExecType(data.OrderStatus);
            order.SetText(data.StatusMsg);
            order.Date = GetDate(data.TradingDay);
            order.Time = GetTime(data.InsertTime);
            order.ReserveChar64 = SgdClientId;
            return order;
        }

        public static OrderType GetOrderPriceType(EnumOrderPriceType type)
        {
            switch (type)
            {
                case EnumOrderPriceType.Market:
                    return OrderType.Market;
                default:
                    return OrderType.Limit;
            }
        }

        public static ExecType GetExecType(EnumOrderStatusType orderStatus)
        {
            return orderStatus switch
            {
                EnumOrderStatusType.AllTraded => ExecType.Trade,
                EnumOrderStatusType.Canceled => ExecType.Cancelled,
                _ => ExecType.New,
            };
        }

        public static OrderStatus GetOrderStatus(EnumOrderStatusType orderStatus)
        {
            return orderStatus switch
            {
                EnumOrderStatusType.AllTraded => OrderStatus.Filled,
                EnumOrderStatusType.Canceled => OrderStatus.Cancelled,
                _ => OrderStatus.New,
            };
        }

        public static HedgeFlagType GetHedgeFlag(EnumHedgeFlagType hedgeFlag)
        {
            return hedgeFlag switch
            {
                EnumHedgeFlagType.Speculation => HedgeFlagType.Speculation,
                EnumHedgeFlagType.Arbitrage => HedgeFlagType.Arbitrage,
                _ => HedgeFlagType.Hedge,
            };
        }

        public static EnumHedgeFlagType GetHedgeFlag(HedgeFlagType hedgeFlag)
        {
            return hedgeFlag switch
            {
                HedgeFlagType.Arbitrage => EnumHedgeFlagType.Arbitrage,
                HedgeFlagType.Hedge => EnumHedgeFlagType.Hedge,
                _ => EnumHedgeFlagType.Speculation
            };
        }

        public static OpenCloseType GetOpenClose(EnumOffsetFlagType offset)
        {
            return offset switch
            {
                EnumOffsetFlagType.Open => OpenCloseType.Open,
                EnumOffsetFlagType.CloseToday => OpenCloseType.CloseToday,
                _ => OpenCloseType.Close,
            };
        }

        public static OrderSide GetOrderSide(EnumDirectionType direction)
        {
            return direction switch
            {
                EnumDirectionType.Buy => OrderSide.Buy,
                _ => OrderSide.Sell,
            };
        }

        public static TradeField GetTradeField(TradeInforField data)
        {
            var trade = new TradeField();
            trade.ID = data.OrderRef;
            trade.ClientID = data.OrderSysID;
            trade.InstrumentID = data.Code;
            trade.AccountID = data.InvestorID;
            trade.TradeID = data.TradeID;
            trade.Side = GetOrderSide(data.Direction);
            trade.Qty = data.Volume;
            trade.Price = data.Price;
            trade.OpenClose = GetOpenClose(data.OffsetFlag);
            trade.HedgeFlag = GetHedgeFlag(data.HedgeFlag);
            trade.Commission = 0;//TODO收续费以后要计算出来
            trade.Time = GetTime(data.TradeTime);
            trade.Date = GetDate(data.TradeDate);
            trade.ReserveChar64 = SgdClientId;
            return trade;
        }

        public static InputOrderInforField GetInputOrder(OrderField order)
        {
            var field = new InputOrderInforField();
            field.OrderRef = order.LocalID;
            field.Code = order.InstrumentID;
            field.ExchangeID = GetExchangeId(order.ExchangeID);
            field.Direction = GetDirection(order.Side);
            field.Offset = GetOffset(order.OpenClose);
            field.HedgeFlag = GetHedgeFlag(order.HedgeFlag);
            field.VolumeTotalOriginal = (int)order.Qty;
            switch (order.Type) {
                case OrderType.Market:
                case OrderType.Stop:
                case OrderType.MarketOnClose:
                case OrderType.TrailingStop:
                    field.OrderPriceType = EnumOrderPriceType.Market;
                    field.LimitPrice = 0;
                    break;
                default:
                    field.OrderPriceType = EnumOrderPriceType.Limit;
                    field.LimitPrice = order.Price;
                    break;
            }
            switch (order.TimeInForce) {
                case TimeInForce.IOC:
                    field.OrderPriceType = EnumOrderPriceType.FAK;
                    break;
                case TimeInForce.FOK:
                    field.OrderPriceType = EnumOrderPriceType.FOK;
                    break;
            }
            return field;
        }

        public static EnumOffsetFlagType GetOffset(OpenCloseType openClose)
        {
            return openClose switch
            {
                OpenCloseType.Close => EnumOffsetFlagType.Close,
                OpenCloseType.CloseToday => EnumOffsetFlagType.CloseToday,
                _ => EnumOffsetFlagType.Open
            };
        }

        public static EnumDirectionType GetDirection(OrderSide side)
        {
            return side == OrderSide.Buy ? EnumDirectionType.Buy : EnumDirectionType.Sell;
        }

        public static EnumExchangeIDType GetExchangeId(string exchangeId)
        {
            switch (exchangeId.ToUpper())
            {
                case "DCE":
                    return EnumExchangeIDType.DCE;
                case "CFFEX":
                    return EnumExchangeIDType.CFFEX;
                case "INE":
                    return EnumExchangeIDType.INE;
                case "CZCE":
                    return EnumExchangeIDType.CZCE;
                case "SHFE":
                    return EnumExchangeIDType.SHFE;
                default:
                    return EnumExchangeIDType.SHFE;
            }
        }

        public static string GetExchangeName(EnumExchangeIDType exchangeId)
        {
            return exchangeId switch
            {
                EnumExchangeIDType.DCE => "DEC",
                EnumExchangeIDType.CFFEX => "CFFEX",
                EnumExchangeIDType.CZCE => "CZCE",
                EnumExchangeIDType.INE => "INE",
                EnumExchangeIDType.SHFE => "SHEF",
                _ => "Unknown"
            };
        }
    }
}